//
//  PositionUtil.m
//  Crazy18-3.1
//
//  Created by qinjilei on 2018/11/6.
//  Copyright © 2018年 fk18go－1. All rights reserved.
//

#import "PositionUtil.h"
#import <math.h>

 
#define  pi  3.1415926535897932384626
#define a   6378245.0
#define  ee   0.00669342162296594323

@implementation PositionUtil


+(BOOL)outOfChina:(double)lat  withLon:(double)lon {
    if (lon < 72.004 || lon > 137.8347)
        return true;
    if (lat < 0.8293 || lat > 55.8271)
        return true;
    return false;
}

/**
 * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
 *
 * @param lat
 * @param lon
 * @return
 */
+ (CLLocationCoordinate2D) gps84_To_Gcj02:(double)lat withLon:(double)lon {
     if ([self outOfChina:lat withLon:lon]) {
        return CLLocationCoordinate2DMake(lat, lon);
    }
    double dLat = [self transformLat:lon - 105.0  withY:lat - 35.0];
    double dLon = [self transformLon:lon - 105.0  withY:lat - 35.0];
    double radLat = lat / 180.0 * pi;
    double magic =  sin(radLat);
    magic = 1 - ee * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
    dLon = (dLon * 180.0) / (a / sqrtMagic *  cos(radLat) * pi);
    double mgLat = lat + dLat;
    double mgLon = lon + dLon;
    return CLLocationCoordinate2DMake(mgLat, mgLon);
}

/**
 * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return
 */
+(CLLocationCoordinate2D)  gcj_To_Gps84:(double)lat withLon:(double)lon {
    CLLocationCoordinate2D gps =[self transform:lat withLon:lon];
    double lontitude = lon * 2 - gps.longitude;
    double latitude = lat * 2 - gps.latitude;
    return CLLocationCoordinate2DMake(latitude, lontitude);
}

/**
 * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
 *
 * @param gg_lat
 * @param gg_lon
 */
+(CLLocationCoordinate2D)   gcj02_To_Bd09:(double)gc_lat  withLon:(double)gc_lon {
    double x = gc_lon, y = gc_lat;
    double z =  sqrt(x * x + y * y) + 0.00002 *  sin(y * pi);
    double theta =  atan2(y, x) + 0.000003 * cos(x * pi);
    double bd_lon = z *  cos(theta) + 0.0065;
    double bd_lat = z *  sin(theta) + 0.006;
    return CLLocationCoordinate2DMake(bd_lat, bd_lon);
}

/**
 * * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * * @param
 * bd_lat * @param bd_lon * @return
 */
+(CLLocationCoordinate2D)    bd09_To_Gcj02:(double)bd_lat  withLon:(double)bd_lon {
    double x = bd_lon - 0.0065, y = bd_lat - 0.006;
    double z =  sqrt(x * x + y * y) - 0.00002 *  sin(y * pi);
    double theta =  atan2(y, x) - 0.000003 *  cos(x * pi);
    double gg_lon = z *  cos(theta);
    double gg_lat = z *  sin(theta);
    return  CLLocationCoordinate2DMake(gg_lat,gg_lon);
}

/**
 * (BD-09)-->84
 *
 * @param bd_lat
 * @param bd_lon
 * @return
 */
+(CLLocationCoordinate2D)  bd09_To_Gps84:(double)bd_lat  withLon:(double)bd_lon {
    
    CLLocationCoordinate2D gcj02 = [self bd09_To_Gcj02:bd_lat withLon:bd_lon];
    CLLocationCoordinate2D map84 =  [self gcj_To_Gps84:gcj02.latitude withLon: gcj02.longitude];
    return map84;
    
}



+(CLLocationCoordinate2D) transform:(double)lat  withLon:(double)lon {
    if ([self outOfChina:lat withLon: lon]) {
        return  CLLocationCoordinate2DMake(lat,lon);
    }
    double dLat = [self transformLat:lon - 105.0  withY:lat - 35.0];
    double dLon = [self transformLon:lon - 105.0 withY:lat - 35.0];
    double radLat = lat / 180.0 * pi;
    double magic =  sin(radLat);
    magic = 1 - ee * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
    dLon = (dLon * 180.0) / (a / sqrtMagic *  cos(radLat) * pi);
    double mgLat = lat + dLat;
    double mgLon = lon + dLon;
    return  CLLocationCoordinate2DMake(mgLat,mgLon);
}

+(double)  transformLat:(double)x  withY:(double)y {
    double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
    + 0.2 *  sqrt( abs(x));
    ret += (20.0 *  sin(6.0 * x * pi) + 20.0 *  sin(2.0 * x * pi)) * 2.0 / 3.0;
    ret += (20.0 *  sin(y * pi) + 40.0 *  sin(y / 3.0 * pi)) * 2.0 / 3.0;
    ret += (160.0 *  sin(y / 12.0 * pi) + 320 *  sin(y * pi / 30.0)) * 2.0 / 3.0;
    return ret;
}

+(double) transformLon:(double)x  withY:(double)y {
    double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
    *  sqrt( abs(x));
    ret += (20.0 *  sin(6.0 * x * pi) + 20.0 *  sin(2.0 * x * pi)) * 2.0 / 3.0;
    ret += (20.0 *  sin(x * pi) + 40.0 *  sin(x / 3.0 * pi)) * 2.0 / 3.0;
    ret += (150.0 *  sin(x / 12.0 * pi) + 300.0 *  sin(x / 30.0
                                                               * pi)) * 2.0 / 3.0;
    return ret;
}


@end
